# coding=utf-8
from django.db import transaction
from django.db.models import Q, F, Sum
from drf_yasg import openapi

from drf_yasg.utils import swagger_auto_schema
from rest_framework import viewsets, status
from MSB_ERP.utils.base_views import MultipleDestoryMixin, MultipleOpenMixin
from MSB_ERP.utils.pagination import GlobalPagination
from rest_framework.decorators import action
from rest_framework.response import Response

from erp_system.models import UserModel
from basic_info.models import CustomerModel
from goods_info.models import GoodsInventoryModel
from warehouse_info.serializer.out_storage_serializer import OnStorySerializer
from warehouse_info.models import SaleDeliverModel, SaleDeliverItemModel


class OutStorageView(viewsets.ModelViewSet, MultipleDestoryMixin, MultipleOpenMixin):
    """
        create:
        仓库(销售)出库单--新增,注意：其中images_list="1,2,3,4";里面是附件的ID

        仓库(销售)出库单新增, status: 201(成功), return: 新增仓库(销售)出库单信息

        destroy:
        仓库(销售)出库单--删除

        仓库(销售)出库单删除, status: 204(成功), return: None

        multiple_delete:
        仓库(销售)出库单--批量删除,必传参数：ids=[1,2,3,4...]

        仓库(销售)出库单批量删除, status: 204(成功), return: None

        update:
        仓库(销售)出库单--修改,注意：其中images_list="1,2,3,4";里面是附件的ID

        仓库(销售)出库单修改, status: 200(成功), return: 修改后的仓库(销售)出库单信息

        partial_update:
        仓库(销售)出库单--局部修改,可以传参任意属性的值，服务器会修改指定的属性值

        仓库(销售)出库单局部修改, status: 200(成功), return: 修改后的仓库(销售)出库单信息

        list:
        仓库(销售)出库单--该接口可以弃用

        仓库(销售)出库单列表信息, status: 200(成功), return: 仓库(销售)出库单信息列表

        retrieve:
        查询某一个仓库(销售)出库单

        查询指定ID的仓库(销售)出库单, status: 200(成功), return: 用户仓库(销售)出库单
        """

    queryset = SaleDeliverModel.objects.all()
    serializer_class = OnStorySerializer
    pagination_class = GlobalPagination # 分页

    def get_queryset(self):
        if self.action == 'find':
            # 接收参数
            number_code = self.request.data.get('number_code', None)  # 单据编号
            keyword = self.request.data.get('keyword', None)  # 商品信息（关键字查询）
            create_time = self.request.data.get('create_time', None)  # 单据创建时间
            update_time = self.request.data.get('update_time', None)  # 最近修改单据的时间
            customer = self.request.data.get('customer', None)  # 客户
            operator_user = self.request.data.get('operator_user', None)  # 操作人的ID
            status = self.request.data.get('status', None)  # 状态
            remark = self.request.data.get('remark', None)  # 备注

            # 创建多条件查询
            query = Q()
            if keyword:  # 关键字查询
                child = Q()
                # 现在的主表是PurchaseStorageModel的主表，查从表的话，要通过从表的外键来进行查询
                child.add(Q(item_list__name_contains=keyword), 'OR')  # 模糊查询货品名称，OR（或）
                child.add(Q(item_list__number_code_contains=keyword), 'OR')  # 模糊查询条码
                child.add(Q(item_list__specification_contains=keyword), 'OR')  # 模糊查询货品规格
                child.add(Q(item_list__model_number=keyword), 'OR')  # 型号查询
                child.add(Q(item_list__color=keyword), 'OR')  # 颜色查询
                query.add(child, 'AND')
            if number_code:
                query.add(Q(item_list__number_code=number_code), 'AND')  # 货品的编号或者批号的查询
            if create_time:
                query.add(Q(invoices_date__gt=create_time), 'OR')  # 查询大于（__gt）单据时间
            if update_time:
                query.add(Q(invoices_date__lt=create_time), 'OR')  # 查询小于（__lt）单据时间
            if customer:
                query.add(Q(customer_id=customer), 'OR') # 查询客户
            if operator_user:
                query.add(Q(operator_user_id=operator_user), 'OR') # 查询操作人
            if status:
                query.add(Q(status=status), 'OR') #  查询状态
            if remark:
                query.add(Q(remark=remark), 'OR') # 查询描述
            return SaleDeliverModel.objects.filter(query).distinct().all()
        else:
            return SaleDeliverModel.objects.all()
    params = openapi.Schema(type=openapi.TYPE_OBJECT,properties={
        'keyword':openapi.Schema(type=openapi.TYPE_STRING,description='条码，名称，规格，型号，颜色等信息'),
        'number_code':openapi.Schema(type=openapi.TYPE_STRING,description='单据编号'),
        'create_time':openapi.Schema(type=openapi.TYPE_STRING,description='创建时间'),
        'update_time':openapi.Schema(type=openapi.TYPE_STRING,description='修改的时间'),
        'customer':openapi.Schema(type=openapi.TYPE_INTEGER,description='客户'),
        'operator_user':openapi.Schema(type=openapi.TYPE_INTEGER,description='操作人'),
        'status':openapi.Schema(type=openapi.TYPE_INTEGER,description='状态'),
        'remark':openapi.Schema(type=openapi.TYPE_INTEGER,description='单据备注')
    })
    page_param = openapi.Parameter(name='page', in_=openapi.IN_QUERY, description="页号", type=openapi.TYPE_INTEGER)
    size_param = openapi.Parameter(name='size', in_=openapi.IN_QUERY, description="每页显示数量", type=openapi.TYPE_INTEGER)
    @swagger_auto_schema(methods=['POST'],request_body=params,operation_description='出库单的搜索过滤',manual_parameters=[page_param,size_param])
    @action(methods=['POST'], detail=False)
    def find(self, request, *args, **kwargs):
        return super(OutStorageView, self).list(request=request, *args, **kwargs)

    """
    自定义的 批量审核的 视图函数
    """
    body_param = openapi.Schema(type=openapi.TYPE_OBJECT, required=['ids', 'user_id'], properties={
        # TYPE_ARRAY列表
        'ids': openapi.Schema(type=openapi.TYPE_ARRAY, items=openapi.Schema(type=openapi.TYPE_INTEGER),
                              description="选择哪些需要批量的ID（主键）列表"),
        'user_id': openapi.Schema(type=openapi.TYPE_INTEGER, description="审核人的用户ID"),
        # 'is_audit': openapi.Schema(type=openapi.TYPE_STRING, description="是否审核，审核：1")
    })

    @swagger_auto_schema(method='put', request_body=body_param, operation_description="批量审核")
    @action(methods=['put'], detail=False)
    @transaction.atomic  # 自动 数据库事务
    def multiple_audit(self, request, *args, **kwargs):
        audit_ids = request.data.get('ids')
        user_id = request.data.get('user_id')  # 用户ID
        # is_audit = request.data.get('is_audit', '1')  # 是否审核，审核：1
        # 为了减少代码量，参数的验证就不写了
        queryset = self.get_queryset().filter(id__in=audit_ids).all()
        check_user = UserModel.objects.get(id=int(user_id))
        for deliver in queryset:  # 出库单
            # 条件是否成立
            if deliver.status != '0':  # 0以后的状态是不能审核的
                return Response(data={'detail': '不能审核，因为订单已生效'}, status=status.HTTP_400_BAD_REQUEST)
            if deliver.status == '0' and deliver.sale:
                if deliver.sale.status != '1' and deliver.sale.status != '2' and deliver.sale.status != '5':
                    return Response(data={'detail': '不能审核，因为关联的销售订单未生效或者已经出库完成'}, status=status.HTTP_400_BAD_REQUEST)

            # 处理审核的业务
            # 业务一：如果有欠款，需要修改客户的末期应收
            if deliver.this_debt: # 如果客户有欠款
                CustomerModel.objects.filter(id=deliver.customer_id)\
                    .update(current_receivable=F('current_receivable') + deliver.this_debt) # 重新赋值给末期应收

            # 业务二：修改关联的销售单，状态：部分出库或者全部出库
            if deliver.sale:
                # 他是一个字典，他包含了字段的名字
                # 查到了已经出库的数量
                out_count_dict = SaleDeliverModel.objects.filter(sale_id=deliver.sale_id).exclude(status='0')\
                .aggregate(sum=Sum('number_count')) # 对出库数量进行累加求和，然后赋值给out_count_dict

                out_count = out_count_dict['sum'] if out_count_dict['sum'] else 0
                if (out_count + deliver.number_count) == deliver.sale.number_count: # 原来出库的数量加上现在出库的数量
                    # 全部出库
                    deliver.sale.status = '3'
                else:
                    # 部分出库
                    deliver.sale.status = '2'
                deliver.sale.save()

            # 业务三：原来的库存 -= 当前出库的数量
            if deliver.item_list.exists():
                for item in deliver.item_list.all(): # 只有加了.all才能进行遍历，不然会说他不是一个可迭代对象
                    GoodsInventoryModel.objects\
                        .filter(goods_id=item.goods_id,warehouse_id=item.warehouse_id)\
                        .update(cur_inventory=F('cur_inventory') - item.sale_count)

            # 审核
            self.get_queryset().filter(id__in=audit_ids).update(status='1', check_user_name=check_user.real_name,
                                                                check_user_id=check_user.id)
            return Response(status=status.HTTP_200_OK)




